#include "stdafx.h"

#include "hwinform.h"
#include "hwinapplication.h"
#include "hwinmenu.h"
#include <typeinfo>

namespace harlinn
{
    namespace windows
    {
        // --------------------------------------------------------------------
        // FormWindowClass
        // --------------------------------------------------------------------
        class FormWindowClass : public WindowClass
        {
        public:
            static String HWIN_EXPORT ClassName;

            HWIN_EXPORT FormWindowClass();
        };

        String HWIN_EXPORT FormWindowClass::ClassName = String(L"HarlinnWindowsFormWindowClassName");

        typedef ControlMessageDispatcher<Form> FormMessageDispatcher;

        HWIN_EXPORT FormWindowClass::FormWindowClass()
        {
            SetName(ClassName);
            WNDPROC procedure = FormMessageDispatcher::WndProc;
            SetProcedure(procedure);
            SetStyle(CS_HREDRAW | CS_VREDRAW);
            SetCursor(LoadCursor(NULL, IDI_APPLICATION));
            
        }


        // --------------------------------------------------------------------
        // Form
        // --------------------------------------------------------------------
        
        HWIN_EXPORT Form::Form( )
            : Base( ),
            shown(false), 
            menuBar(0)
        {
        }


        HWIN_EXPORT Form& Form::Close()
        {
            SendMessage(WM_CLOSE);
            return *this;
        }

        HWIN_EXPORT std::shared_ptr<WindowClass> Form::GetWindowClass() const
        {
            auto windowClass = Application::GetWindowClass(FormWindowClass::ClassName);
            if(!windowClass)
            {
                auto newWindowClass = std::make_shared<FormWindowClass>();
                newWindowClass->Register();
                return newWindowClass;
            }
            return windowClass;
        }

        HWIN_EXPORT DWORD Form::GetStyle() const
        {
            auto result = Base::GetStyle();
            result &= ~(WS_CHILD | WS_TABSTOP | WS_VISIBLE);
            result |= WS_OVERLAPPEDWINDOW;
            return result;
        }

        HWIN_EXPORT Form& Form::DrawMenuBar()
        {
            if(::DrawMenuBar(GetSafeHandle()) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT std::shared_ptr<MenuBar> Form::GetMenu() const
        {
            return menuBar;
        }
        HWIN_EXPORT Form& Form::SetMenu(std::shared_ptr<MenuBar> theMenu)
        {
            
            menuBar = theMenu;
            if(IsValid())
            {
                HMENU hMenu = nullptr;
                if(menuBar)
                {
                    hMenu = menuBar->GetHandle()->GetHMENU();
                }
                if(::SetMenu(GetSafeHandle(),hMenu) == FALSE)
                {
                    ThrowLastOSError();
                }

                DrawMenuBar();
            }
            return *this;
        }


        HWIN_EXPORT void Form::HandleMessage(Message& message)
        {
            switch(message.message)
            {
                case WM_ACTIVATE:
                    this->DoOnActivate(message);
                    break;
                case WM_ACTIVATEAPP:
                    this->DoOnActivateApp(message);
                    break;
                case WM_DEVMODECHANGE:
                    this->DoOnDevModeChange(message);
                    break;
                case WM_ENDSESSION:
                    this->DoOnEndSession(message);
                    break;
                case WM_FONTCHANGE:
                    this->DoOnFontChange(message);
                    break;
                case WM_GETMINMAXINFO:
                    this->DoOnGetMinMaxInfo(message);
                    break;
                case WM_ICONERASEBKGND:
                    this->DoOnIconEraseBackground(message);
                    break;
                case WM_MOUSEACTIVATE:
                    this->DoOnMouseActivate(message);
                    break;
                case WM_PAINTICON:
                    this->DoOnPaintIcon(message);
                    break;
                case WM_POWERBROADCAST:
                    this->DoOnPowerBroadcast(message);
                    break;
                case WM_QUERYDRAGICON:
                    this->DoOnQueryDragIcon(message);
                    break;
                case WM_QUERYENDSESSION:
                    this->DoOnQueryEndSession(message);
                    break;
                case WM_QUERYOPEN:
                    this->DoOnQueryOpen(message);
                    break;
                case WM_SETTINGCHANGE:
                    this->DoOnSettingChange(message);
                    break;
                case WM_TIMECHANGE:
                    this->DoOnTimeChange(message);
                    break;
                default:
                    Base::HandleMessage(message);
                    break;
            }
        }

        HWIN_EXPORT void Form::DoOnHandleCreated( )
        {
            Base::DoOnHandleCreated( );
            if(menuBar)
            {
                HMENU hMenu = menuBar->GetHandle()->GetHMENU();
                if(::SetMenu(GetSafeHandle(),hMenu) == FALSE)
                {
                    ThrowLastOSError();
                }
                DrawMenuBar();
            }
            
        }


        HWIN_EXPORT void Form::DoOnActivate(Message& message)
        {
            OnActivate(this,message);
        }

        HWIN_EXPORT void Form::DoOnActivateApp(Message& message)
        {
            OnActivateApp(this,message);
        }

        HWIN_EXPORT void Form::DoOnDevModeChange(Message& message)
        {
            OnDevModeChange(this,message);
        }

        HWIN_EXPORT void Form::DoOnEndSession(Message& message)
        {
            OnEndSession(this,message);
        }

        HWIN_EXPORT void Form::DoOnFontChange(Message& message)
        {
            OnFontChange(this,message);
        }

        HWIN_EXPORT void Form::DoOnGetMinMaxInfo(Message& message)
        {
            OnGetMinMaxInfo(this,message);
        }

        HWIN_EXPORT void Form::DoOnIconEraseBackground(Message& message)
        {
            OnIconEraseBackground(this,message);
        }

        HWIN_EXPORT void Form::DoOnMouseActivate(Message& message)
        {
            OnMouseActivate(this,message);
        }

        HWIN_EXPORT void Form::DoOnPaintIcon(Message& message)
        {
            OnPaintIcon(this,message);
        }

        HWIN_EXPORT void Form::DoOnPowerBroadcast(Message& message)
        {
            OnPowerBroadcast(this,message);
        }

        HWIN_EXPORT void Form::DoOnQueryDragIcon(Message& message)
        {
            OnQueryDragIcon(this,message);
        }

        HWIN_EXPORT void Form::DoOnQueryEndSession(Message& message)
        {
            OnQueryEndSession(this,message);
        }

        HWIN_EXPORT void Form::DoOnQueryOpen(Message& message)
        {
            OnQueryOpen(this,message);
        }

        HWIN_EXPORT void Form::DoOnSettingChange(Message& message)
        {
            OnSettingChange(this,message);
        }
        
        HWIN_EXPORT void Form::DoOnShowWindow(Message& message)
        {
            if(!shown)
            {
                Rectangle rect = this->GetClientRect();

                Message wmSize = message;
                wmSize.message = WM_SIZE;
                wmSize.wParam = 0;
                wmSize.lParam = (rect.Height() << 16) | rect.Width();
                this->HandleMessage(wmSize);
                shown = true;
                this->DoOnShown();
            }
            Base::DoOnShowWindow(message);
        }

        HWIN_EXPORT void Form::DoOnShown()
        {
            OnShown(this);
        }

        HWIN_EXPORT void Form::DoOnTimeChange(Message& message)
        {
            OnTimeChange(this,message);
        }


    }
}